Create by fall on 22 Nov 2022 Recently revised in 10 Feb 2025
脚本文件
使用
bash 可以用于书写批量执行的脚本,或者是 npm
中的脚本(node_modules 下的 .bin
目录中,有三类脚本,分别在不同的环境下执行)
首行内容固定,以 #!
开始,称为 shebang 指令,用于指定运行该脚本的解析器。
命名一个 bash 脚本:hello.sh
,并在脚本内填写以下内容
#!/bin/sh
VAR="world"
echo "Hello $VAR"
$ bash hello.sh
输出内容为:Hello world
Shebang 指令是所有脚本语言通用的,也会出现 node 或者其他形式的书写方式。
执行脚本
作为可执行文件执行
# 给所有用户添加执行权限
chmod a+x hello.sh # 同 chmod 755 hello.sh
./hello.sh
指定解析器执行
使用 bash 作为解析器执行 hello.sh
$ bash hello.sh
作为全局命令
# 移动,并把后缀去掉,这样更像命令
mv hello.sh /usr/local/bin/hello
hello
# Hello Shell!
# 创建软连接也可以执行该命令
ln -s ./hello.sh /usr/local/bin/hello
# 命令别名也可以,注意只能在当前窗口中生效
alias hello="bash ~/hello.sh"
hello
# Hello Shell!
注释
# 这是一个内联 Bash 注释
# 多行注释中冒号,空格,引号,缺一不可。
: '
这是 bash 多行注释
bash echo
'
配置
可以在一下位置进行 bash 的全局配置
- Bash:
~/.bash_profile
- ZSH:
~/.zshrc
输入输出
输出
echo
:打印内容的标准输出。printf
:格式化输出,类似 C 的 printf 函数。
echo "hello"
printf "保留两位小数:e = %1.2f" $E
# 2.72
通过 >
符号可以将内容输出到文件
echo "老铁,整一个" > file.txt
# >> 表示向文件内追加内容
echo "整一个!" >> file.txt
输入
read:从标准输入读取用户输入
# 展示输入提示,用户输入值被保存到变量name中
read -p "请输入任意值" name
# 利用重定向,从文件中读取输入值
read name1 name2 < file.txt
变量
NAME="Fall" # 注意:赋值符号前后均不能有空格
echo ${NAME} # => Fall (变量)
echo $NAME # => Fall (变量)
echo "$NAME" # => Fall (变量)
echo '$NAME' # => $NAME (字符串原样输出) 单引号和双引号不同
echo "${NAME}!" # => Fall! (变量)
变量的作用域可以分成三类:
- 环境变量:能在当前 shell 及其子 shell 中使用,使用
declare -x
或export
导出。 - 全局变量:只能在当前 shell 进程内使用,默认。
- 局部变量:只能在函数内使用,使用命令
local
声明。
变量除了保存值以外,还可能绑定某些属性,比如 只读、只能存储数值、作用域。
declare
命令可以赋予变量一些特殊的属性。
declare -r CONST_INT=2 # 设置只读变量,同 readonly 命令声明的变量
declare -i a_int=3 # 数字类型变量
declare -x ENV_VAR=value # 设置为环境变量
尽管这看起来像是变量声明,不过也可以作用于已有变量。
var=val
declare -r var
默认参数
系统提供了一些默认参数提供调用
表示 | 描述 |
---|---|
$0 | 脚本本身的名称 |
$1 … $9 | 参数 1 ... 9 |
${10} | 位置参数 10 |
$# | 参数数量 |
$$ | shell 的进程 id |
$* | 所有参数,作为一个整体 |
$@ | 所有参数,依次分割 |
$- | 当前选项 |
$_ | 上一个命令的最后一个参数 |
$? | 上一个命令的执行结果,0 为成功,其他为失败 |
假设有如下脚本 test
#!/bin/sh
pink="Ori ddd"
echo $pink
echo $(pwd)
echo $0
echo $1
echo $*
我们通过该方式执行
# 执行该命令
bash test -g -m
# 得到输出为
# Ori ddd
# /e/Full-stuck-study/命令行
# test.sh
# -g
# -g -m
$@
和 $-
的区别
#!/bin/bash
echo "当前使用: \$*:"
for arg in "$*"
do
echo "Hello $arg"
done
echo "当前使用: \$@:"
for arg in "$@"
do
echo "Hello $arg"
done
# 执行命令 sh ./ddd.sh js shell python
当前使用: $*:
Hello JS shell Python
当前使用: $@:
Hello JS
Hello shell
Hello Python
大括号扩展
echo {A,B}
# A B
echo {A,B}.js
# A.js B.js
{1..5}
# 1 2 3 4 5
{A..F}
# A B C D E F
$(( expression )) # 表达式计算后的值
参数扩展
代码 | 描述 |
---|---|
${FOO%suffix} | 删除后缀 |
${FOO#prefix} | 删除前缀 |
${FOO%%suffix} | 去掉长后缀 |
${FOO##prefix} | 删除长前缀 |
${FOO/from/to} | 替换第一个匹配项 |
${FOO//from/to} | 全部替换 |
${FOO/%from/to} | 替换后缀 |
${FOO/#from/to} | 替换前缀 |
表示 | 描述 |
---|---|
${FOO:0:3} | 字符串或数组的切片 |
${FOO:(-3):3} | 从右边开始的子串 |
${#FOO} | 参数 FOO 的长度 |
${FOO:-val} | $FOO ,如果未设置,则为 val |
${FOO:=val} | 如果未设置,则将 $FOO 设置为 val |
${FOO:+val} | val 如果设置了$FOO |
${FOO:?message} | 如果 $FOO 未设置,则显示消息并退出 |
foo='you are beautiful'
echo ${foo%ful}
pink="what"
echo ${#pink} # 4
函数
定义函数
#!/bin/sh
pink="Ori"
get_name() {
echo "John ${pink}"
}
echo "You are $(get_name)"
# 执行结果
# You are John 执行结果
其中,函数的定义也可以写为
function get_name(){
echo "John $pink"
}
# 函数的执行必须通过 $() 或者 `` 进行包裹
$(get_name)
`get_name`
# 二者等价
命令替换
#!/bin/sh
# 如果想要执行一些命令,可以使用 `command` 或者 $(command) 使用命令 command,并且两者可以替换
echo `pwd` # 等同于 $(pwd)
# 输出:
# /e/Full-stuck-study/命令行
echo "where am i $(pwd)"
echo "where am i `pwd`"
执行流程控制
顺序执行命令,使用 ;
进行分割
# 一次性输入多个命令
command1; command2; command3
&&
和 ||
command && command1 || command2
# command 执行为 true ,执行 command1 否则执行 command2
条件句
test
命令是一个专门用于条件判断的内置命令,它支持一系列条件表达式,当条件成立时退出码为 0,不成立时为 1。
test expr
# 或者使用简写
[ expr ]
# 还有一种拓展的test,在原有的基础上支持了正则匹配
[[ expr ]]
#!/bin/sh
string="wtf"
# string="" # 为空时,也为 false
if [ -z "$string" ]; then
echo "String is empty"
elif [ -n "$string" ]; then
echo "String is not empty"
fi
find
if [ -d "data/" ];then
echo "dir exits"
else
echo "dir not exits"
fi
参考文章
作者 | 链接 |
---|---|
jaywcjlove | https://github.com/jaywcjlove/reference/blob/main/docs/bash.md |
czpcalm | https://juejin.cn/post/7130983293347954718 |
czpcalm | https://juejin.cn/post/7130982053528469511 |